#include <Arduino.h>
#include <WiFi.h>
#include "PubSubClient.h"
#include <HTTPUpdate.h>
#include "esp_http_client.h"
#include "ArduinoJson.h"
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"
#include <String>
#include <iostream>
#include "driver/i2c.h"
#include "driver/adc.h"

#include "config.hpp"
#include "Utils.hpp"

LightUtils utils;
//初始化任务句柄
TaskHandle_t Flag_Monitor_Handle;
TaskHandle_t Task_Display_Handle;
TaskHandle_t AI_conversation_Handle;

//audio
#include "Audio1.h"
#include "Audio2.h"
#include <ArduinoJson.h>
#include <ArduinoWebsockets.h>

bool startPlay = false;
bool lastsetence = false;
bool isReady = false;
bool ac_control = false;
unsigned long urlTime = 0;

int noise = 50;
HTTPClient https;

hw_timer_t *timer = NULL;
uint8_t adc_start_flag = 0;
uint8_t adc_complete_flag = 0;

Audio1 audio1;
Audio2 audio2(false, 3, I2S_NUM_1);

void voicePlay();
void gain_token(void);
void getText(String role, String content);
void checkLen(JsonArray textArray);
int getLength(JsonArray textArray);
float calculateRMS(uint8_t *buffer, int bufferSize);
void ConnServer1();
void processReceivedData(const char *data);
DynamicJsonDocument doc(4000);
JsonArray text = doc.to<JsonArray>();

String url = "";
String url1 = "";
String Date = "";
DynamicJsonDocument gen_params(const char *appid, const char *domain);

String askquestion = "";
String Answer = "";

using namespace websockets;

WebsocketsClient webSocketClient1;

void getTimeFromServer(void);
String getUrl(String Spark_url, String host, String path, String Date);

//chartgpt
boolean autochartgptanswerFlag = false;
String chartgptanswer = ""; //GPT回答的答案
String chartgptquestion = "";//平台下发的问题给硬件，手动按钮下发

boolean chartgptaudio = false;
String audiourl = "";
int16_t volume= 10;

boolean chartgptautoupload = false;//触发语音的flag

boolean autoUploadChartGPTFlag = false;//是否自动上传gpt的flag
void autoChartGPTStatus();//函数声明

void onMessageCallback1(WebsocketsMessage message);
void onEventsCallback1(WebsocketsEvent event, String data);

#define SHT31_I2C_ADDRESS 0x44               // SHT31的I2C地址
#define SHT31_CMD_MEASURE 0x2C06 // 启动测量命令
// static const char *TAG = "SHT31";

void i2c_master_init();
void sht31_read(float *temperature, float *humidity);

float convertToPPM(float voltage);
// 将电压转换为光强度（勒克斯）
float convertToLux(float voltage);

// ST7735驱动芯片的图形和字体库
#include <TFT_eSPI.h>
#include <SPI.h>

// 调用库，引脚在User_Setup.h中定义
TFT_eSPI tft = TFT_eSPI();

void ftf_display(void);
void alarmAction(void);

// 自动化任务 列表
JsonArray combineAutoArr ;
// 解析自动化任务缓存
StaticJsonDocument<1024*2> docauto;
// 自动化任务列表显示的flag
boolean combineAutoArrFlag = false;
// 自动化任务数量
int8_t demand_count = 0;
// 是否马上拉取自动化任务的flag
boolean getCombinemonitorFlag = false;

void combinecontrollFunc(JsonArray cmdcombine);
void combinemonitorFunc(JsonArray cmdcombine);
void getCombineAutoByCidHardware(String cid);

// 红外 自定义发射 -空调ac控制--海尔空调
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Haier.h>
IRHaierACYRW02 haier_ac(kIrLed);
void AC_Control(void* pvParameters);
void controlAC(ACControlParams* params);

#include <string.h>
#define uint unsigned int

// delay for half a second
int delayval = 1000;

// 重启设备--阈值
int restartCount = 0;

void send_fotamsg(String fotastatus ,String toastmsg ,String loading ,u8_t loadingmaxtime ,String progress);

// 重启设备flag标识
boolean esp_restartFlag = false;
// 是否自动上传的flag
boolean autoUploadFlag = false;

//fota的状态
int fota_status = 0;
boolean fotaFlag = false;
String updateurl= "";
String updateversion= "";
int totalProgress = -1;

// 定时器初始化
hw_timer_t *tim1 = NULL;
int tim1_IRQ_count = 0;

//全局的TCP连接，在发送UDP的时候，可以检测TCP获取的ID是否变化，以防服务端挂了后客户端不知道
WiFiClient client;
PubSubClient mqttclient(client);

// #include "esp_task_wdt.h"
// #define TWDT_TIMEOUT_S  30

//-----------网络时间获取-----------//
#define NTP1 "ntp1.aliyun.com"
#define NTP2 "ntp2.aliyun.com"
#define NTP3 "ntp3.aliyun.com"

//时区设置函数，东八区（UTC/GMT+8:00）写成8*3600
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;   //夏令时填写3600，否则填0

void reconnect();


// 连接WiFi网络
void wifiConnect(const char *wifiData[][2], int numNetworks)
{
    WiFi.disconnect(true);

    for (int i = 0; i < numNetworks; ++i)
    {
        const char *ssid = wifiData[i][0];
        const char *password = wifiData[i][1];

        Serial.print("Connecting to ");
        Serial.println(ssid);

        WiFi.begin(ssid, password);
        uint8_t count = 0;
        while (WiFi.status() != WL_CONNECTED)
        {
            Serial.print(".");
            count++;
            if (count >= 6)
            {
                Serial.printf("\r\n-- wifi connect fail! --\r\n");
                break;
            }
            vTaskDelay(500);
        }

        if (WiFi.status() == WL_CONNECTED)
        {
            Serial.printf("\r\n-- wifi connect success! --\r\n");
            Serial.print("IP address: ");
            Serial.println(WiFi.localIP());
            Serial.println("Free Heap: " + String(ESP.getFreeHeap()));
            return; // 如果连接成功，退出函数
        }
    }
}

// 获取自动化任务
void getCombineAutoByCidHardware(String cid)
{
    HTTPClient http;

    String nonce = utils.md5str(reporttime +'0'+ random(1000));

    TimeStruct stc =  utils.setClock(SRCCID);

    int64_t signt = stc.timeStamp ;

    String did = utils.md5str(reporttime +'0'+ random(1000));

    String str5 = "api/getCombineAutoByCidHardware_appkey=" + appkey + "_cid=" + cid + "_did=" + did +"_nonce="+nonce+ "_signt="+(signt *1000) +"_"+ secretkey;

    String str6 = utils.urlEncode(str5);

    String sign =  utils.md5str(str6);

    String url = combinecontroll_url  + "?cid=" + cid + "&did="+did+ "&nonce="+nonce+ "&signt="+(signt *1000)+ "&appkey="+ appkey + "&sign="+sign;
    Serial.println(url);
    // Serial.print(url);

    http.begin(url); //访问服务器地址

    // Serial.print("[HTTP] GET...n");
    // start connection and send HTTP header
    int httpCode = http.GET();

    // httpCode will be negative on error
    if(httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        // Serial.printf("[HTTP] GET... code: %dn", httpCode);

        // file found at server
        if(httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            Serial.println(payload);

                deserializeJson(docauto, payload);

                boolean status = docauto["status"];
                if (status)
                {
                    combineAutoArr =  docauto["data"]["list"].as<JsonArray>();;

                    demand_count = combineAutoArr.size();
                    deviceStatus = "get combineauto ok";

                    // 获取成功的flag
                    combineAutoArrFlag = true;
                    //自动拉取的flag
                    getCombinemonitorFlag = false;

                }else{
                  Serial.printf("获取自动化任务失败1");

                }

        }else{
          Serial.printf("获取自动化任务失败2");

        }
    } else {
        Serial.printf("[HTTP] GET... failed, error: %sn", http.errorToString(httpCode).c_str());
    }
    http.end();

}

// 获取设备信息
void getDeviceByMac(String mac){

 uint8_t wifi_failedcount = 0;

  while (SRCCID == "")
  {
    /* code */

    HTTPClient http;

    String nonce = utils.md5str(reporttime +'0'+ random(1000));

    TimeStruct stc =  utils.setClock(SRCCID);

    int64_t signt = stc.timeStamp ;

    String did = utils.md5str(reporttime +'0'+ random(1000));

    String str5 = "api/getDeviceByMac_appkey=" + appkey+"_did="+ did+ "_mac=" + mac +"_nonce="+nonce+ "_signt="+(signt *1000)+"_version="+ version +"_"+ secretkey;

    String str6 = utils.urlEncode(str5);

    String sign =  utils.md5str(str6);

    String url = getsrccid_url  + "?mac="+mac+ "&version="+version+ "&did="+did+ "&nonce="+nonce+ "&signt="+(signt *1000)+ "&appkey="+ appkey + "&sign="+sign;
    Serial.println(url);
    // Serial.print(url);

    http.begin(url); //访问服务器地址

    // Serial.print("[HTTP] GET...n");
    // start connection and send HTTP header
    int httpCode = http.GET();

    // httpCode will be negative on error
    if(httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        // Serial.printf("[HTTP] GET... code: %dn", httpCode);

        // file found at server
        if(httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            Serial.println(payload);

                StaticJsonDocument<1024> doc;
                deserializeJson(doc, payload);

                boolean status = doc["status"];
                if (status)
                {
                    const char* cid =  doc["data"]["cid"];

                    String newcid = cid;
                    SRCCID = newcid.c_str();
                    Serial.printf(newcid.c_str());

                    const char* clientmqttClientId =  doc["data"]["mqttClientId"];
                    String newmqttClientId = clientmqttClientId;
                    mqtt_mqttClientId = newmqttClientId.c_str();

                    const char* clientusername =  doc["data"]["username"];
                    String newusername = clientusername;
                    mqtt_username = newusername.c_str();

                    const char* clientpasswd =  doc["data"]["passwd"];
                    String newpasswd = clientpasswd;
                    mqtt_passwd = newpasswd.c_str();

                    const char* clientmqttHostUrl =  doc["data"]["mqttHostUrl"];
                    String newmqttHostUrl = clientmqttHostUrl;
                    mqtt_mqttHostUrl = newmqttHostUrl.c_str();

                    mqtt_port =  doc["data"]["port"];

                    const char* clientudphost =  doc["data"]["udphost"];
                    String newudphost = clientudphost;
                    udp_host = newudphost.c_str();

                    udp_port =  doc["data"]["udpport"];

                    const char* clientphotourl =  doc["data"]["photourl"];
                    String newphotourl = clientphotourl;
                    photourl = newphotourl.c_str();

                    const char* clientmqtt_pub_topic =  doc["data"]["mqtt_pub_topic"];
                    String mqtt_pub_topic = clientmqtt_pub_topic;
                    mqtt_pub_topicsss = mqtt_pub_topic.c_str();

                    const char* clientmqtt_sub_topic =  doc["data"]["mqtt_sub_topic"];
                    String mqtt_sub_topic = clientmqtt_sub_topic;
                    mqtt_sub_topicsss = mqtt_sub_topic.c_str();

                    const char* clientcombinecontrollurl =  doc["data"]["combinecontrollurl"];
                    String combinecontrollurl = clientcombinecontrollurl;
                    combinecontroll_url = combinecontrollurl.c_str();

                }

        }else{
          Serial.printf("获取CID失败延时5s");

        }
    } else {
        Serial.printf("[HTTP] GET... failed, error: %sn", http.errorToString(httpCode).c_str());
    }
    http.end();
    // 延时3S继续获取
     if (SRCCID =="")
     {
       delay(3000);

        wifi_failedcount ++;
        if (wifi_failedcount >=5)
        {
          digitalWrite(alarm,HIGH);
          wifi_failedcount = 0;
        }

     }


  }
    wifi_failedcount = 0;
    digitalWrite(alarm,LOW);

}

// 当升级开始时，打印日志
void update_started() {
  totalProgress= -1;
  send_fotamsg("fota_started","升级开始","show",5,"--");
  Serial.println("CALLBACK:  HTTP update process started");
}

// 当升级中，打印日志
void update_progress(int cur, int total) {
  float aa = (float)cur;
  float bb = (float)total;
    int grs = (int)(aa/bb *100);
    String progress = (String) grs ;

  if (  totalProgress != grs)
  {
    /* code */
        send_fotamsg("fota_progress","升级中","show",5,progress);

  }
      totalProgress = grs;


  Serial.printf("CALLBACK:  HTTP update process at %d of %d bytes...%s...%d... \n", cur, total,progress,grs);
}

// 当升级结束时，打印日志
void update_finished() {
  totalProgress= -1;
    send_fotamsg("fota_finished","升级完成","hiden",0,"--");
  Serial.println("CALLBACK:  HTTP update process finished");
}

//当升级失败时，打印日志
void update_error(int err) {
  totalProgress= -1;
  send_fotamsg("fota_error","FOTA升级失败","hiden",0,"--");
  Serial.printf("CALLBACK:  HTTP update fatal error code %d\n", err);
}

// 升级信息上报
void send_fotamsg(String fotastatus ,String toastmsg ,String loading ,u8_t loadingmaxtime ,String progress){

    StaticJsonDocument<1024> doc;
        deserializeJson(doc, REPORT_COMMON_TEMPLATE);
       // setClock();
        doc["cid"] = SRCCID;
        doc["datatype"] = "dictionary";
        doc["version"] = version;
        doc["cmdtype"] = "cmd_fotaack";
        doc["loadingmaxtime"] = loadingmaxtime;
        doc["toastmsg"] = toastmsg;
        doc["loading"] = loading ;
        doc["progress"] = progress;
        doc["fotastatus"] = fotastatus;
        doc["reporttime"] = reporttime;

        String nonce = utils.md5str(reporttime +'0'+ random(1000));
        doc["nonce"]= nonce;

        TimeStruct stc =  utils.setClock(SRCCID);

        int64_t signt = stc.timeStamp ;

        doc["signt"] = (signt *1000)  ;
        String cidstr = SRCCID;

        String did = utils.md5str(reporttime +'0'+ random(1000));
        doc["did"] =  did;

        char  buffer[1024];
        size_t n = serializeJson(doc, buffer);
        Serial.println(buffer);

    //   const char *mqtt_pub_topic = mqtt_pub_topicsss.c_str();

        if (mqttclient.publish( mqtt_pub_topicsss.c_str(), buffer,n)) {
            // Serial.printf("auto topic fota [%s] ok\n", mqtt_pub_topic);

        } else {
            Serial.printf("auto topic fota [%s] fail\n",  mqtt_pub_topicsss.c_str());
        }

}

// 设备升级更新检测
void updateDevice(String upUrl,String updateversion){

    String ver = (String)version;
    String newver = (String)updateversion;
    Serial.println(ver);
    Serial.println(newver);

    if (ver == newver)
    {
        Serial.println("version equal ");

        //FOTA开始的通知 mqtt 小程序提示
        send_fotamsg("fota_checked","已是最新版本","hiden",0,"--");
        return ;
    }
    else if ( upUrl == ""){

       //FOTA开始的通知 mqtt 小程序提示
        send_fotamsg("fota_error","FOTA升级地址错误","hiden",0,"--");

        Serial.println("url error");
        return ;
    }
    //FOTA开始的通知 mqtt 小程序提示
    String toast = "";

    Serial.println("start update");
    WiFiClient UpdateClient = client;

    //如果是旧版esp32 SDK，需要删除下面四行，旧版不支持，不然会报错
    httpUpdate.onStart(update_started);//当升级开始时
    httpUpdate.onEnd(update_finished);//当升级结束时
    httpUpdate.onProgress(update_progress);//当升级中
    httpUpdate.onError(update_error);//当升级失败时

    t_httpUpdate_return ret = httpUpdate.update(UpdateClient, upUrl);
    switch(ret) {
        case HTTP_UPDATE_FAILED:      //当升级失败
            toast = "FOTA升级失败";
            Serial.println("[update] Update failed.");
            break;
        case HTTP_UPDATE_NO_UPDATES:  //当无升级
            toast = "无FOTA升级";
            Serial.println("[update] Update no Update.");
            break;
        case HTTP_UPDATE_OK:         //当升级成功
            toast = "FOTA升级成功";
            Serial.println("[update] Update ok.");
            break;
    }
}

/********http请求处理函数*********/
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    if (evt->event_id == HTTP_EVENT_ON_DATA)
    {
        httpResponseString.concat((char *)evt->data);
    }
    return ESP_OK;
}

// led alarm初始化
void cmd_GPIO_Init(){
    //设置io口为输出模式

    pinMode(alarm,OUTPUT);
    digitalWrite(alarm, LOW);

    pinMode(rc1,OUTPUT);
    digitalWrite(rc1, LOW);

    pinMode(rc2,OUTPUT);
    digitalWrite(rc2, LOW);

    pinMode(rc3,OUTPUT);
    digitalWrite(rc3, LOW);

    pinMode(rc4,OUTPUT);
    digitalWrite(rc4, LOW);

    //设置io口为输出模式
    pinMode(led1,OUTPUT);
    digitalWrite(led1, HIGH);

    pinMode(led2,OUTPUT);
    digitalWrite(led2, HIGH);

}

// 上传GPT问题
void autoChartGPTStatus(){

    StaticJsonDocument<1024> doc;
    deserializeJson(doc, REPORT_CHARTGPT_TEMPLATE);

    TimeStruct stc =  utils.setClock(SRCCID);
    reporttime = stc.reporttime;
    doc["reporttime"] = reporttime;
    doc["question"] = chartgptquestion;
    doc["version"] = version;
    doc["cid"] = SRCCID;
    String nonce = utils.md5str(reporttime +'0'+ random(1000));
    doc["nonce"]= nonce;
    int64_t signt = stc.timeStamp ;
    doc["signt"] = (signt *1000) ;
    String cidstr = SRCCID;
    String did = utils.md5str(reporttime +'0'+ random(1000));
    doc["did"] =   did;
    char  buffer[1024];
    size_t n = serializeJson(doc, buffer);
    Serial.println(buffer);
    String  DDS= mqtt_pub_topicsss ;
    const char *mqtt_pub_topic = DDS.c_str();
    if (mqttclient.publish(mqtt_pub_topic,buffer,n)) {
        Serial.printf("auto topic [%s] ok\n", mqtt_pub_topic);

    } else {
        Serial.printf("auto topic [%s] fail\n", mqtt_pub_topic);
    }

}

// 10s自动上报数据
void autoDataStatus(){
    unsigned char rc1_status = digitalRead(rc1) ;
    unsigned char rc2_status = digitalRead(rc2) ;
    unsigned char rc3_status = digitalRead(rc3) ;
    unsigned char rc4_status = digitalRead(rc4) ;
    unsigned char alarm_status = digitalRead(alarm) ;
    unsigned char led1_status = digitalRead(led1) ;
    unsigned char led2_status = digitalRead(led2) ;

    StaticJsonDocument<1024> doc;
    deserializeJson(doc, REPORT_DATA_TEMPLATE);

    TimeStruct stc =  utils.setClock(SRCCID);
    reporttime = stc.reporttime;
    fileName = stc.fileName;
    
    if (old_sht31_temp!=0 && old_sht31_humi !=0)
    {
          doc["temperature"] = old_sht31_temp;
          doc["humidity"] = old_sht31_humi;
    }

    doc["reporttime"] = reporttime;
    doc["alarm"] = alarm_status ? "open" : "close";
    doc["led1"] = led1_status ? "open" : "close";
    doc["led2"] = led2_status ? "open" : "close";

    doc["ac"] = ac;
    doc["ac_temp"] = ac_temp;
    doc["ac_fan"] = ac_fan;

    doc["rc1"] = rc1_status ? "open" : "close";
    doc["rc2"] = rc2_status ? "open" : "close";
    doc["rc3"] = rc3_status ? "open" : "close";
    doc["rc4"] = rc4_status ? "open" : "close";

    doc["version"] = version;
    doc["demand"] = demand_count;

    doc["cid"] = SRCCID;
    doc["photoname"] = lastphotofileName;

    doc["airquality"] = old_airc;
    doc["lux"] = old_illu;
    doc["volume"] = volume;

    String cidstr = SRCCID;

    String did = utils.md5str(reporttime +'0'+ random(1000));
    doc["did"] =   did;

    char  buffer[1024];
    size_t n = serializeJson(doc, buffer);


    Serial.println(buffer);

    const char *mqtt_pub_topic = mqtt_pub_topicsss.c_str();
    if (mqttclient.publish( mqtt_pub_topicsss.c_str(),buffer,n)) {
        Serial.printf("auto topic [%s] ok\n",  mqtt_pub_topicsss.c_str());
        restartCount = 0;

    } else {
        Serial.printf("auto topic [%s] fail\n",  mqtt_pub_topicsss.c_str());
        restartCount++;

        //三次错误，就直接重启设备
        if (restartCount >=3)
        {
            alarmLevel = 3;
            restartCount = 0;
            Serial.printf("restarxxx3");
            // esp_restartFlag = true;//继续联网别重启
        }
    }

}

// 中断服务函数
void tim1Interrupt()
{
    timerAlarmEnabled(tim1);
    autoUploadFlag = true;
}

// 定时器初始化
void timerInit(){
  tim1 = timerBegin(0, 80, true);
  timerAttachInterrupt(tim1, tim1Interrupt, true);
  timerAlarmWrite(tim1, 10000000ul, true);  //10s 10000000ul
  timerAlarmEnable(tim1);

}

// 0级别--告警关闭
void alarm_close(){
    digitalWrite(alarm,LOW);
}

// 1级别--告警
void alarm_low(){

    digitalWrite(alarm,HIGH);
    delay(10);
    digitalWrite(alarm,LOW);
    delay(200);

}
// 2级别--告警
void alarm_medium(){

    digitalWrite(alarm,HIGH);
    delay(100);
    digitalWrite(alarm,LOW);
    delay(100);

}

// 3级别--告警
void alarm_height(){
    digitalWrite(alarm,HIGH);
}

// 告警执行
void alarmAction(){

    switch (alarmLevel)
    {
        case 3:
            alarm_height();
            break;
        case 2://wifi断开
            alarm_medium();
            break;
        case 1://4路继电器打开
            alarm_low();
            break;
        case 0://4路继电器打开
            alarm_close();
            break;
        default:
            break;
    }

}

// 自动化任务执行  10*1024内存 20条指令
void combinemonitorFunc(JsonArray cmdcombine){

    String demand_and= "demand_and";
    String demand_or= "demand_or";

    String compare_valuetype_String = "String";
    String compare_valuetype_Number = "Number";

    // 外设的值
    String compare_key_rc1 = "rc1";
    String compare_key_rc2 = "rc2";
    String compare_key_rc3 = "rc3";
    String compare_key_rc4 = "rc4";

    // 字段传感器的采集的值
    String compare_key_temperature = "temperature";
    String compare_key_humidity = "humidity";
    String compare_key_airquality = "airquality";

    // 运算符
    String compare_type_dy   = ">";
    String compare_type_dydy = ">=";
    String compare_type_hdy  = "=";
    String compare_type_xydy = "<=";
    String compare_type_xy   = "<";
    String compare_type_bdy  = "!=";

    // JsonArray array = doc.as<JsonArray>();
    for(auto dict : cmdcombine) {

        String autotype = dict["autotype"];

        JsonArray demandArr =  dict["demand"];
        JsonArray paramsArr =  dict["params"];

        // 数据运算比较
        if (autotype == demand_and)//与计算
        {
            // 是否执行的flag
            int8_t combineFlag = 0;

            for(JsonObject dict1 : demandArr) {
                String compare_key = dict1["compare_key"];
                String compare_type = dict1["compare_type"];
                String compare_valuetype = dict1["compare_valuetype"];
                auto compare_value = dict1["compare_value"];

                String compare_value_string = "";
                int    compare_value_number = 0;

                // 温度
                if (compare_key == compare_key_temperature)
                {
                    compare_value_number = old_temp;

                } else if (compare_key == compare_key_humidity)
                {
                    compare_value_number = old_humi;

                } else if (compare_key == compare_key_rc1)
                {
                    compare_value_string = (old_rc1 == "I" ? "open":"close");

                } else if (compare_key == compare_key_rc2)
                {
                    compare_value_string = (old_rc2 == "I" ? "open":"close");

                } else if (compare_key == compare_key_rc3)
                {
                    compare_value_string = (old_rc3 == "I" ? "open":"close");

                } else if (compare_key == compare_key_rc4)
                {
                    compare_value_string = (old_rc4 == "I" ? "open":"close");

                }else
                {
                   Serial.printf("compare_key err:%s" , compare_key);

                }

                // 计算数据比较
                if (compare_type == compare_type_dy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_number > compare_value)
                        {
                            combineFlag++;
                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_string > compare_value)
                        {
                            combineFlag++;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }else if (compare_type ==  compare_type_dydy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if ( compare_value_string >= compare_value)
                        {
                            combineFlag++;
                        }else{

                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_number >= compare_value)
                        {
                            combineFlag++;
                        }else{


                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }else if (compare_type ==  compare_type_hdy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_string == compare_value)
                        {
                            combineFlag++;
                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if ( compare_value_number == compare_value)
                        {
                            combineFlag++;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }else if (compare_type ==  compare_type_xydy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_string <= compare_value)
                        {
                            combineFlag++;
                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_number <= compare_value)
                        {
                            combineFlag++;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }else if (compare_type ==  compare_type_xy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_string < compare_value)
                        {
                            combineFlag++;
                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_number < compare_value)
                        {
                            combineFlag++;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }else if (compare_type ==  compare_type_bdy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_string != compare_value)
                        {
                            combineFlag++;
                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_number != compare_value)
                        {
                            combineFlag++;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }else{
                   Serial.printf("compare_type55 err:%s" , compare_type);
                   Serial.println(" ");
                }

            }
            // 最后是否执行的判断，是根据与全部满足执行
            if (combineFlag == demandArr.size())
            {
                // 触发执行
                combinecontrollFunc(paramsArr);
            }else{

            }
        }else if (autotype == demand_or)//或计算
        {
            // 是否执行的flag
            boolean combineFlag = false;

            for(JsonObject dict1 : demandArr) {
                String compare_key = dict1["compare_key"];
                String compare_type = dict1["compare_type"];
                String compare_valuetype = dict1["compare_valuetype"];
                auto compare_value = dict1["compare_value"];

                String compare_value_string = "";
                int    compare_value_number = 0;

                // 温度
                if (compare_key == compare_key_temperature)
                {
                    compare_value_number = old_temp;

                } else if (compare_key == compare_key_humidity)
                {
                    compare_value_number = old_humi;

                } else if (compare_key == compare_key_rc1)
                {
                    compare_value_string = (old_rc1 == "I" ? "open":"close");

                } else if (compare_key == compare_key_rc2)
                {
                    compare_value_string = (old_rc2 == "I" ? "open":"close");

                } else if (compare_key == compare_key_rc3)
                {
                    compare_value_string = (old_rc3 == "I" ? "open":"close");

                } else if (compare_key == compare_key_rc4)
                {
                    compare_value_string = (old_rc4 == "I" ? "open":"close");

                }else
                {
                    Serial.println("ERROR 2");
                }
                // Serial.println(compare_type);

                // 计算数据比较
                if (compare_type == compare_type_dy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_string > compare_value)
                        {
                            combineFlag = true;
                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_number > compare_value)
                        {
                            combineFlag = true;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }else if (compare_type == compare_type_dydy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if ( compare_value_string >= compare_value)
                        {
                            combineFlag = true;
                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_number >= compare_value)
                        {
                            combineFlag = true;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }
                else if (compare_type == compare_type_hdy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_string == compare_value)
                        {
                            combineFlag = true;
                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_number == compare_value)
                        {
                            combineFlag = true;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }else if (compare_type == compare_type_xydy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_string <= compare_value)
                        {
                            combineFlag = true;
                        }

                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if ( compare_value_number <= compare_value)
                        {
                            combineFlag = true;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }

                }else if (compare_type == compare_type_xy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_string < compare_value)
                        {
                            combineFlag = true;
                        }
                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_number < compare_value)
                        {
                            combineFlag = true;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }
                }else if (compare_type == compare_type_bdy)
                {
                    if (compare_valuetype == compare_valuetype_String )
                    {
                        if (compare_value_string != compare_value)
                        {
                            combineFlag = true;
                        }
                    }else if(compare_valuetype == compare_valuetype_Number )
                    {
                        if (compare_value_number != compare_value)
                        {
                            combineFlag = true;
                        }
                    }else{
                        Serial.println("ERROR 3");
                    }
                }else{
                    Serial.println("ERROR 2");
                }

                // 最后是否执行的一个flag
                if (combineFlag)
                {
                    // 触发执行
                    combinecontrollFunc(paramsArr);
                    // 跳出当前这一个执行，进行下一个判断
                    break;
                }
            }

        }else{
            Serial.printf("autotype err:%s" , autotype);
            Serial.println("-");
        }

    }
}

//一键执行  2*1024内存 20条指令
void combinecontrollFunc(JsonArray cmdcombine){

    String exe_controll= "exe_controll";
    String exe_delay= "exe_delay";

    Serial.println("combinecontroll begin");
    Serial.println(cmdcombine.size());
    Serial.println("combinecontroll end");

    // JsonArray array = doc.as<JsonArray>();
    for(JsonObject dict : cmdcombine) {
        String cmdtype =  dict["cmdtype"];
        Serial.println("cmdtype:"+cmdtype);

        if (cmdtype == exe_controll)
        {
            auto  cmddata = dict["cmddata"];
            String sensorname = cmddata["sensorname"];
            String sensorcmd= cmddata["sensorcmd"];
            Serial.println(sensorname);
            Serial.println(sensorcmd);

            if (sensorname == "rc1"){
                if(sensorcmd == "open")
                {
                    digitalWrite(rc1,HIGH);
                }else if(sensorcmd == "close")
                {
                    digitalWrite(rc1,LOW);
                }else{}

            }else if (sensorname == "rc2"){
                if(sensorcmd == "open")
                {
                       digitalWrite(rc2,HIGH);

                }else if(sensorcmd == "close")
                {
                       digitalWrite(rc2,LOW);

                }else{
                }

            }else if (sensorname == "rc3"){
                if(sensorcmd == "open")
                {
                   digitalWrite(rc3,HIGH);

                }else if(sensorcmd == "close")
                {
                   digitalWrite(rc3,LOW);

                }else{
                }

            }else if (sensorname == "rc4"){
                if(sensorcmd == "open")
                {
                   digitalWrite(rc4,HIGH);

                }else if(sensorcmd == "close")
                {
                   digitalWrite(rc4,LOW);

                }else{
                }

            }else if (sensorname == "alarm"){
                if(sensorcmd == "open")
                {
                    digitalWrite(alarm,HIGH);

                }else if(sensorcmd == "close")
                {
                    digitalWrite(alarm,LOW);

                }else{
                }

            }else if (sensorname == "led1"){
                if(sensorcmd == "open")
                {
                    // digitalWrite(alarm,LOW);

                }else if(sensorcmd == "close")
                {
                    // digitalWrite(alarm,HIGH);
                }else{
                }

            }else if (sensorname == "exe_alarm1"){
                if(sensorcmd == "open")
                {
                    digitalWrite(alarm,HIGH);
                    delay(100);
                    digitalWrite(alarm,LOW);
                }else if(sensorcmd == "close")
                {
                    digitalWrite(alarm,LOW);
                }else{
                }

            }else if (sensorname == "exe_alarm2"){
                if(sensorcmd == "open")
                {
                    digitalWrite(alarm,HIGH);
                    delay(100);
                    digitalWrite(alarm,LOW);
                    delay(100);
                    digitalWrite(alarm,HIGH);
                    delay(100);
                    digitalWrite(alarm,LOW);

                }else if(sensorcmd == "close")
                {
                    digitalWrite(alarm,LOW);

                }else{
                }

            }else{
                Serial.println("unknown sensorname");

            }

        }else if (cmdtype == exe_delay)
        {
            auto  cmddata = dict["cmddata"];
            int timevalue = cmddata["timevalue"];
            Serial.printf("timevalue:%d" ,timevalue);
            delay(timevalue);
        }

    }

}

// 平台下发的远控指令-回调
void callback(char* topic, byte* payload, unsigned int length)
{
    Serial.println(topic);

    //json数据解析
    StaticJsonDocument<1024*3> doc;
    DeserializationError error = deserializeJson(doc, payload, length);
    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.c_str());
    }
    // Serial.println();
    serializeJsonPretty(doc, Serial);

    String did= doc["did"];

    // 远控类型
    String cmdType = doc["cmdtype"];

    String cmd_combinecontroll= "cmd_combinecontroll";
    String cmd_combinemonitor= "cmd_combinemonitor";
    String cmd_controll= "cmd_controll";
    String cmd_status= "cmd_status";
    String cmd_statusack= "cmd_statusack";

    String cidstr = SRCCID ;

    String signt = doc["signt"];

    if (cmdType == cmd_controll)
    {
        // 远控命令
        Serial.println("cmd_controll");
        auto  cmddata = doc["cmddata"];
        String sensorname = cmddata["sensorname"];
        String sensorcmd= cmddata["sensorcmd"];

        if (sensorname == "rc1"){
            Serial.println(sensorname);
            if(sensorcmd == "open")
            {
                Serial.println("open");
                digitalWrite(rc1,HIGH);
                autoUploadFlag = true;

            }else if(sensorcmd == "close")
            {
                Serial.println("close");
                digitalWrite(rc1,LOW);
                autoUploadFlag = true;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "rc2"){
            Serial.println(sensorname);
            if(sensorcmd == "open")
            {
                Serial.println("open");
               digitalWrite(rc2,HIGH);
                autoUploadFlag = true;

            }else if(sensorcmd == "close")
            {
                Serial.println("close");
               digitalWrite(rc2,LOW);
                autoUploadFlag = true;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "rc3"){
            Serial.println(sensorname);
            if(sensorcmd == "open")
            {
                Serial.println("open");
               digitalWrite(rc3,HIGH);
                autoUploadFlag = true;

            }else if(sensorcmd == "close")
            {
                Serial.println("close");
               digitalWrite(rc3,LOW);
                autoUploadFlag = true;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "rc4"){
            Serial.println(sensorname);
          if(sensorcmd == "open")
            {
                Serial.println("open");
               digitalWrite(rc4,HIGH);
                autoUploadFlag = true;

            }else if(sensorcmd == "close")
            {
                Serial.println("close");
               digitalWrite(rc4,LOW);
                autoUploadFlag = true;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "alarm"){
            Serial.println(sensorname);
            if(sensorcmd == "open")
            {
                Serial.println("open");
                alarmLevel = 3;
                // digitalWrite(alarm,HIGH);
                autoUploadFlag = true;

            }else if(sensorcmd == "close")
            {
                Serial.println("close");
                alarmLevel = 0;
                // digitalWrite(alarm,LOW);
                autoUploadFlag = true;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "ac"){//控制空调
            Serial.println(sensorname);

            ACControlParams* params = new ACControlParams();
            params->sensorname = "ac";
            params->sensorcmd = sensorcmd;
            params->cmddata = cmddata;
            //新建空调控制任务，将其创建在核心1运行，控制结束后任务自动删除
            xTaskCreatePinnedToCore(AC_Control, "AC Control", 2*1024, params, 10, NULL, 1);
            
        }else if (sensorname == "restart"){
            Serial.println(sensorname);

            if(sensorcmd == "open")
            {
                Serial.println("open");
                autoUploadFlag = true;
                esp_restartFlag = true;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "status"){
            Serial.println(sensorname);

            if(sensorcmd == "open")
            {
                Serial.println("open");
                //  -- 基础数据查询
                autoUploadFlag = true;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "fota"){
            Serial.println(sensorname);

            if(sensorcmd == "open")
            {
                updateversion = "";
                updateurl = "";

                Serial.println("open");
                //  -- 远程更新FOTA
                auto  extdata = cmddata["extdata"];
                String updateurlCC= extdata["updateurl"];
                updateurl = updateurlCC;
                String updateversions =  extdata["updateversion"];
                Serial.println(updateurl +":"+ updateversions);
                updateversion = updateversions;

                fotaFlag = true;
                fota_status = 1;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "combinemonitor"){
            Serial.println(sensorname);

            if(sensorcmd == "open")
            {
                Serial.println("open");
                getCombinemonitorFlag = true;

            }else{
                Serial.println(sensorcmd);
            }


        }else if (sensorname == "chartgptanswer"){
            Serial.println(sensorname);

            if(sensorcmd == "open")
            {

              Serial.println("open");
              chartgptanswer = "";//清空原来内容
              //读取扩展参数
              auto  extdata = cmddata["extdata"];
              String ccanswer= extdata["answer"];
              Serial.println("chartgptanswer:");
              Serial.println(chartgptanswer);

              chartgptanswer = ccanswer;

// ------------------------------播放汉字-------------------------------------

              audio2.connecttospeech(chartgptanswer.c_str(), "zh");

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "chartgptquestion"){//平台直接下发问题给硬件
            Serial.println(sensorname);

            if(sensorcmd == "open")
            {
              Serial.println("open");
              chartgptquestion = "";//清空原来内容

              //读取扩展参数
              auto  extdata = cmddata["extdata"];
              String ccquestion= extdata["question"];//问题文字
              chartgptquestion = ccquestion;

              autoUploadChartGPTFlag  = true;//设备上报给平台MQTT方式，等待AI回答

// ------------------------------播放汉字-------------------------------------
                askquestion = chartgptquestion;
                audio2.connecttospeech(askquestion.c_str(), "zh");

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "chartgptsetvolume"){//平台直接下发声音的音量
            Serial.println(sensorname);

            if(sensorcmd == "open")
            {
              Serial.println("open");
              //读取扩展参数
              auto  extdata = cmddata["extdata"];
              volume= extdata["volume"];//音量读取
              audio2.setVolume(volume);
              autoUploadFlag = true;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "chartgptaudio"){//chartgptaudio
            Serial.println(sensorname);

            if(sensorcmd == "open")
            {

              Serial.println("open");
              //读取扩展参数
              auto  extdata = cmddata["extdata"];
              String ccaudiourl= extdata["audiourl"];

                   audiourl = ccaudiourl;
                   chartgptaudio = true;

            }else{
                Serial.println(sensorcmd);
            }

        }else if (sensorname == "chartgptautoupload"){
            Serial.println(sensorname);

            if(sensorcmd == "open")
            {
                Serial.println("open");
                // chartgptquestion = "我是" + SRCCID +  "号设备,请叫我靓仔";//实际测试时候把整个去掉，从硬件采集数据
                //  -- 开启语音自动上传
                chartgptautoupload = true;

            }else if(sensorcmd == "close")
            {
                    Serial.println("close");
                    chartgptautoupload = false;

                    autoUploadFlag = true;

            }else{
                Serial.println(sensorcmd);
            }

        } else{
             Serial.println(sensorname);
        }

    }else if (cmdType == cmd_status){
         //  -- 基础数据查询
        Serial.println("cmd_status");
        autoUploadFlag = true;

    }else if (cmdType == cmd_combinecontroll){
         //  -- 一键下发
        Serial.println("cmd_combinecontroll");       
        auto params = doc["cmdcombine"]["params"];//数组
        JsonArray cmdcombine = params.as<JsonArray>();
        autoUploadFlag = true;
        combinecontrollFunc(cmdcombine); //2*1024内存 20条指令
    }else if (cmdType == cmd_combinemonitor){
         //  -- 自动化执行
        Serial.println("cmd_combinemonitor");
        getCombinemonitorFlag = true;
        autoUploadFlag = true;

        // combineAutoArrFlag = false;
        // DeserializationError error = deserializeJson(docauto, orinalpayload, length);
        // if (error) {
        //     Serial.print(F("deserializeJson() failed: "));
        //     Serial.println(error.c_str());
        // }
        // JsonArray cmdcombine = docauto["cmdcombine"].as<JsonArray>();
        // combineAutoArr = cmdcombine;//数组
        // autoUploadFlag = true;
        // combineAutoArrFlag = true;

    }else if (cmdType == cmd_statusack){
        //远控的ACK返回
        Serial.println("cmd_statusack");
        String reporttime = doc["reporttime"];
        old_reporttime = reporttime;

    }else{
        //其他类型
        Serial.println("ERROR 00");
        Serial.println(cmdType.c_str());
        Serial.println("ERROR 01");

    }

    // 返回远控的ACK消息
    if (cmdType != cmd_statusack && cmdType != cmd_status)
    {
        StaticJsonDocument<1024> docack;
        deserializeJson(docack, REPORT_CONTROLLACK_TEMPLATE);
        TimeStruct stc =  utils.setClock(SRCCID);
        reporttime = stc.reporttime;
        fileName = stc.fileName;

        docack["did"] =  did;
        docack["datatype"] =  "dictionary";
        docack["cid"] = SRCCID;

        docack["reporttime"] = reporttime;
        docack["version"] = version;

        int64_t timer1_cnt=esp_timer_get_time(); //获取本地时间戳
        // printf("time cnt:%lld\r\n",timer1_cnt); //打印时间戳

        docack["signt"] = timer1_cnt;
        String cidstr = SRCCID;

        char  buffer[1024];
        size_t n = serializeJson(docack, buffer);

        // const char *mqtt_pub_topic = mqtt_pub_topicsss.c_str();
        if (mqttclient.publish( mqtt_pub_topicsss.c_str(), buffer,n)) {
            Serial.printf("auto topic ack [%s] ok\n",  mqtt_pub_topicsss.c_str());

        } else {
            Serial.printf("auto topic ack [%s] fail\n",  mqtt_pub_topicsss.c_str());
        }

    }

}

// void wdt_init(){
//     rtc_wdt_protect_off();     //看门狗写保护关闭 关闭后可以喂狗
//     //rtc_wdt_protect_on();    //看门狗写保护打开 打开后不能喂狗
//     //rtc_wdt_disable();       //禁用看门狗
//     rtc_wdt_enable();          //启用看门狗
//     rtc_wdt_set_time(RTC_WDT_STAGE0, 30000); // 设置看门狗超时 8000ms.则reset重启
// }

#include <esp32-hal.h>
#include <lwip/apps/sntp.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>

/**
 * @brief 设置时区和NTP服务器和并校对时间
 * @param [in] posix_tz 表示posix规范的时间戳。例如"UTC-8"表示东八区（北京时间）
 * @param [in] server_cnt NTP服务器的数量，超过三个的会被抛弃
 * @param [in] ... NTP服务器，C风格字符串指针类型，数量应与server_cnt对应
 * @attention 函数不会保证WiFi连接正常
 * @example set_time("UTC-8", 3, "time2.cloud.tencent.com", "ntp1.aliyun.com", "ntp.ntsc.ac.cn");
 * @example set_time("UTC+6", 2, "time2.cloud.tencent.com", "192.168.0.2");
 */
void set_time(const char *const posix_tz, const int server_cnt,const char* server1, const char* server2, const char* server3)
{
	sntp_setoperatingmode(SNTP_OPMODE_POLL);

    sntp_setservername(0, (char*)server1);
    sntp_setservername(1, (char*)server2);
    sntp_setservername(2, (char*)server3);

	sntp_init();
	setenv("TZ", posix_tz, 1);
	tzset();
	while (time(NULL) < 1580000000) // 阻塞，直到时间同步
		yield();
	sntp_stop();
}

// 屏幕初始化
void tft_setup(){
    tft.init();
    tft.setRotation(1);

}

// 屏幕显示
void ftf_display()
{
// 用灰色填充屏幕，以便我们可以看到带有和不带有背景颜色定义的打印效果
    // tft.fillScreen(TFT_BLACK);
    // 第一行清屏
    tft.fillRect(0, 0, tft.width(), 2* 7, TFT_BLACK);

    // 将“光标”设置在显示器的左上角(0,0)，并选择字体2
    // （在使用'tft.println'打印时，光标将自动移动到下一行
    // 或者如果有足够的空间，光标将停留在同一行上）
    tft.setCursor(0, 0, 2);

    // 将字体颜色设置为白色，背景为黑色，将文本大小乘数设置为1
    tft.setTextColor(TFT_WHITE, TFT_BLACK);
    tft.setTextSize(1);
    // 现在我们可以使用“print”类在屏幕上绘制文本
    // tft.print(old_reporttime);
    // tft.println(" " + (String)demand_count + "");


    // if (demand_count>0)
    // {
    //     tft.print(old_reporttime);
    //     tft.println(" " + (String)demand_count + "");

    // }else{
    //     tft.println(old_reporttime);

    // }
    
    tft.println(old_reporttime);


    // 设备状态
    // tft.setTextColor(TFT_WHITE, TFT_BLACK);
    // tft.setTextFont(2);
    // tft.print("status:  ");
    // tft.println(deviceStatus);
    tft.println("");

    // 将字体颜色设置为黄色，没有背景，设置为字体7
    // tft.setTextColor(TFT_WHITE, TFT_BLACK);
    // tft.setTextFont(2);
    // tft.println("Temp: 36℃    Humi: 78%");

    // 将字体颜色设置为红色，背景为黑色，设置为字体4
    tft.setTextColor(TFT_WHITE, TFT_BLACK);

    // 温度
    // tft.setTextFont(4);
    tft.setTextSize(1);
    tft.print("T: ");
    tft.print(old_sht31_temp);
    tft.print("'C");

    // 湿度
    tft.print("   H: ");
    tft.print(old_sht31_humi);
    tft.print("%");

    //  空气质量
    tft.print("  A: ");
    tft.print(old_airc );
    tft.println(" ");

    //  tft.println("ppm");
    //  tft.println("ppm");

    //光照
    tft.setCursor(0, 60);
    tft.print("L: ");
    tft.print(old_illu);
    // tft.println(" ");
     tft.print("lux");

    // 音量
    tft.print("  V: ");
    tft.print(volume);
    tft.print("%");

    // 自动化个数
    tft.print("  M:");
    tft.print(" " + (String)demand_count );
    tft.println(" ");
    tft.println("");

    tft.setCursor(0, 90);
    tft.print("RC1: ");
    tft.print(old_rc1);

    tft.print("  RC2: ");
    tft.print(old_rc2);

    tft.print("  RC3: ");
    tft.print(old_rc3 );
    tft.println(" ");

    tft.print("RC4: ");
    tft.print(old_rc4);

    tft.print("  ALM: ");
    tft.print(old_alarm);

    tft.print("  AC : ");
    tft.print(old_ac);
    tft.println(" ");

}

// 子线程刷新屏幕
void TaskDisplay(void *param){

    float c_temp,c_humi;

// 用灰色填充屏幕，以便我们可以看到带有和不带有背景颜色定义的打印效果
    tft.fillScreen(TFT_BLACK);
    while (1)
    {
        vTaskDelay(500/portTICK_PERIOD_MS);

        unsigned char rc1_status = digitalRead(rc1) ;
        unsigned char rc2_status = digitalRead(rc2) ;
        unsigned char rc3_status = digitalRead(rc3) ;
        unsigned char rc4_status = digitalRead(rc4) ;
        unsigned char alarm_status = digitalRead(alarm) ;

        sht31_read(&c_temp, &c_humi);

        float  airc_voltage = (analogRead(MQ135_PIN))*(3.3/4095.0);
        float  c_airc = convertToPPM(airc_voltage);

        float illu_voltage = ((analogRead(TEMT6000_PIN))*(3.3/4095.0))*2;
        float c_illu = convertToLux(illu_voltage);
        
        old_sht31_temp = c_temp;
        old_sht31_humi = c_humi;

        //  if ( c_airc != old_airc )
        // {
        //     autoUploadFlag = true;
        // }
        // if ( c_illu != old_illu )
        // {
        //     autoUploadFlag = true;
        // }
        old_airc = c_airc;
        old_illu = c_illu;


    // 设备有打开任何外设时，设备进行告警播报1S一次
    // if (rc1_status || rc2_status || rc3_status || rc4_status)
    // {
    //     alarmLevel = 1; //告警1

    // }else{
    //     alarmLevel = 0; //告警消除
    // }


        old_rc1 = rc1_status ? "I" : "O";
        old_rc2 = rc2_status ? "I" : "O";
        old_rc3 = rc3_status ? "I" : "O";
        old_rc4 = rc4_status ? "I" : "O";

        old_ac = ac =="open" ? "I" : "O";
        
        unsigned char old_alarm_status = digitalRead(alarm) ;
        old_alarm = alarm_status ? "I" : "O";


        if (getCombinemonitorFlag)
        {
            getCombineAutoByCidHardware(SRCCID);
        }

        // 监控实时数据
       if (combineAutoArrFlag)
       {
        // Serial.println("--------------------------begin---------------------------");
            if (demand_count>0)
            {
                deviceStatus = "demand [ " + (String)demand_count + " ]";

            }else{
                deviceStatus = "demand [ " + (String)demand_count + " ]";
            }

            combinemonitorFunc(combineAutoArr);
        // Serial.println("--------------------------end---------------------------");

       }

        TimeStruct stc =  utils.setClock(SRCCID);
        old_reporttime = stc.displaytime;

        ftf_display();
        alarmAction();
    }
}

void AIconversation(void *param)
{
    while(1){
        vTaskDelay(1/portTICK_PERIOD_MS);
        // Serial.print("task1 running");
        // Serial.println(xPortGetCoreID());
        webSocketClient1.poll();
        // delay(10);
        if (startPlay)
        {
            voicePlay();
        }

        audio2.loop();

        if (audio2.isplaying == 1)
        {
            digitalWrite(led1, LOW);
        }
        else
        {
            digitalWrite(led1, HIGH);
            if ((urlTime + 240000 < millis()) && (audio2.isplaying == 0))
            {
                urlTime = millis();
                getTimeFromServer();
                url = getUrl("ws://spark-api.xf-yun.com/v3.5/chat", "spark-api.xf-yun.com", "/v3.5/chat", Date);
                url1 = getUrl("ws://ws-api.xfyun.cn/v2/iat", "ws-api.xfyun.cn", "/v2/iat", Date);
            }
        }

        if(chartgptaudio){
            chartgptaudio= false;
// ------------------------------播放歌曲--------------------------------------
            String audioStreamURL = audiourl;
            Serial.println(audioStreamURL.c_str());
            audio2.connecttohost(audioStreamURL.c_str());
        }

        if (chartgptautoupload) //按下开关才能录音--网络下发的命令
        {
            chartgptautoupload = false;

            audio2.isplaying = 0;
            startPlay = false;
            isReady = false;
            Answer = "";
            Serial.printf("Start recognition\r\n\r\n");

            adc_start_flag = 1;
            // Serial.println(esp_get_free_heap_size());

            if (urlTime + 240000 < millis()) // 超过4分钟，重新做一次鉴权
            {
                urlTime = millis();
                getTimeFromServer();
                url = getUrl("ws://spark-api.xf-yun.com/v3.5/chat", "spark-api.xf-yun.com", "/v3.5/chat", Date);
                url1 = getUrl("ws://ws-api.xfyun.cn/v2/iat", "ws-api.xfyun.cn", "/v2/iat", Date);
            }
            askquestion = "";
            // audio2.connecttospeech(askquestion.c_str(), "zh");
            ConnServer1();
            // delay(6000);
            // audio1.Record();
            adc_complete_flag = 0;

            // Serial.println(text);
            // checkLen(text);
        }
         // 是否上报gpt
        if (autoUploadChartGPTFlag)
        {
            autoUploadChartGPTFlag = false;
            autoChartGPTStatus();
        }
    }
}

void FlagMonitor(void *param)
{
    while (true)
    {
        vTaskDelay(10/portTICK_PERIOD_MS);
        if (!mqttclient.connected()) {
            //断网重来开始
            Serial.println("do loop 断网重连开始");
            reconnect();
        }
        // client loop
        mqttclient.loop();
        // Serial.print("loop running");
        // Serial.println(xPortGetCoreID());

        // 是否FOTA
        if (fotaFlag)
        {
            deviceStatus = "FOTA";
            fotaFlag = false;
            updateDevice(updateurl,updateversion);
        }

        // 是否上报设备状态 10s中断上报
        if (autoUploadFlag)
        {
            autoUploadFlag = false;
            autoDataStatus();
        }

        if (esp_restartFlag)
        {
            esp_restartFlag = false;
            mqttclient.disconnect();
            delay(200);
            esp_restart();
        }

    }
}

void AC_Control(void* pvParameters)
{
    while (true)
    {
        Serial.println("ac_control task run");
        ACControlParams* params = (ACControlParams*)pvParameters; 
        // 执行空调控制
        controlAC(params);
        // 释放内存
        delete params;
        // 删除任务
        vTaskDelete(NULL);
    }
}

void setup() {
    // 屏幕初始化
    tft_setup();
    setCpuFrequencyMhz(240);//将ESP32主频设置为240MHz，最高主频运行

    xTaskCreatePinnedToCore(
        TaskDisplay       // 这个任务运行的函数
        ,  "Task Display" //  给人看的名字
        ,  5*1024        // 任务栈的大小，用于存储任务运行时的上下文信息。简单来说，就是最多存这么多信息
        ,  NULL // 任务参数。要么没有填NULL；要么必须为无类型指针
        ,  2  // 优先级
        ,  &Task_Display_Handle // 任务的句柄，用于管理和控制任务
        ,  0                 // 指定任务分配的核心
    );

    deviceStatus = "init Serial";

    // 红外发射初始化V2
    // 必须一开始就初始化，不然红外灯发热厉害--引脚1不用就注销掉
    // haier_ac.begin();

    Serial.begin(115200);
    Serial.setDebugOutput(true);
    while (!Serial) {
        /* code */
    }
    deviceStatus = "init GPIO";

    cmd_GPIO_Init();
    i2c_master_init();
    // ESP_ERROR_CHECK(i2c_master_init());//iIC初始化

    deviceStatus = "connect wifi";

    // utils.setup_wifi(ssid, passwd);
    int numNetworks = sizeof(wifiData) / sizeof(wifiData[0]);
    utils.setup_wifi(wifiData, numNetworks);

    configTime(8 * 3600, 0, NTP1, NTP2, NTP3);

    // set_time("UTC-8", 3, "time2.cloud.tencent.com", "ntp1.aliyun.com", "ntp.ntsc.ac.cn");

    String mac = utils.getmac();

    deviceStatus = "get device info";

    getDeviceByMac(mac);
    getCombineAutoByCidHardware(SRCCID);

    deviceStatus = "mqtt connecting";

    // connect mqtt server
    mqttclient.setServer(mqtt_mqttHostUrl.c_str(), mqtt_port);
    mqttclient.setCallback(callback);
    mqttclient.setKeepAlive(60);
    while (!mqttclient.connect(mqtt_mqttClientId.c_str(), mqtt_username.c_str(), mqtt_passwd.c_str())) {
        Serial.println("mqtt connect fail, reconnect");
        deviceStatus = "mqtt connect err";

        int numNetworks = sizeof(wifiData) / sizeof(wifiData[0]);
        utils.setup_wifi(wifiData, numNetworks);

    }

    Serial.println("mqtt connected!");
    deviceStatus = "mqtt connected!";

    // sub topic
    boolean ret = mqttclient.subscribe(mqtt_sub_topicsss.c_str());
    if (ret != true) {
        Serial.printf("mqtt subscribe topic [%s] fail\n", mqtt_sub_topicsss.c_str());
    }
    Serial.printf("mqtt subscribe topic [%s] ok\n", mqtt_sub_topicsss.c_str());

    // wdt_init();
    // Serial.printf("wdt_init\n");

    //定时器
    timerInit();

    audio1.init();

    getTimeFromServer();

    audio2.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
    audio2.setVolume(volume);

    // String Date = "Fri, 22 Mar 2024 03:35:56 GMT";
    url = getUrl("ws://spark-api.xf-yun.com/v3.5/chat", "spark-api.xf-yun.com", "/v3.5/chat", Date);
    url1 = getUrl("ws://ws-api.xfyun.cn/v2/iat", "ws-api.xfyun.cn", "/v2/iat", Date);
    urlTime = millis();
    
    xTaskCreatePinnedToCore(
        AIconversation      // 这个任务运行的函数
        ,  "AI conversation"// 给人看的名字
        , 10*1024           // 任务栈的大小，用于存储任务运行时的上下文信息。简单来说，就是最多存这么多信息
        , NULL              // 任务参数。要么没有填NULL；要么必须为无类型指针
        , 10                // 优先级
        , &AI_conversation_Handle              // 任务的句柄，用于管理和控制任务
        , 1                 // 指定任务分配的核心
    );


    xTaskCreatePinnedToCore(
        FlagMonitor       // 这个任务运行的函数
        ,  "Flag Monitor" // 给人看的名字
        ,  10*1024        // 任务栈的大小，用于存储任务运行时的上下文信息。简单来说，就是最多存这么多信息
        ,  NULL           // 任务参数。要么没有填NULL；要么必须为无类型指针
        ,  10             // 优先级
        ,  &Flag_Monitor_Handle // 任务的句柄，用于管理和控制任务
        ,  0              // 指定任务分配的核心
    );
    // vTaskStartScheduler();
}

void reconnect() {
    deviceStatus = "reconnect mqtt";

    while (!mqttclient.connected()) {

        alarmLevel = 3; //告警
        // alarmAction();

        // 重新打开wifi链接、
        Serial.println("reset wifi ...");

        int numNetworks = sizeof(wifiData) / sizeof(wifiData[0]);
        utils.setup_wifi(wifiData, numNetworks);


        Serial.print("Attempting MQTT connection...");
        // Attempt to connect
        if (mqttclient.connect(mqtt_mqttClientId.c_str(), mqtt_username.c_str(), mqtt_passwd.c_str())) {
            Serial.println("connected");
            alarmLevel = 0; //告警消除
            // 连接成功时订阅主题
            deviceStatus = "connect mqtt ok";
            // const char *mqtt_sub_topic =  mqtt_sub_topicsss.c_str();
            mqttclient.subscribe(mqtt_sub_topicsss.c_str());
            autoUploadFlag = 1;

        } else {

          Serial.print("failed, rc=");
          Serial.print(mqttclient.state());
          Serial.println(" try again in 3 seconds");
          // Wait 5 seconds before retrying
          delay(3000);
        }
    }
}

float convertToPPM(float voltage) {
    // 参考值: 假设 1.5V 对应 400 ppm, 3V 对应 1000 ppm（这是个假设，可以根据具体的气体校准）
    float ppm = 0;
    if (voltage <= 1.5) {
        ppm = (voltage / 1.5) * 400; // 线性插值
    } else {
        ppm = ((voltage - 1.5) / (3.0 - 1.5)) * (1000 - 400) + 400;
    }
    return ppm;
}

// 将电压转换为光强度（勒克斯），使用 10kΩ 电阻
float convertToLux(float voltage) {
    float resistorValue = 10000.0; // 假设使用 10kΩ 电阻
    float current = voltage / resistorValue; // 电流 = 电压 / 电阻
    float lux = current * 1000000.0; // 将电流 µA 转换为勒克斯
    return lux;
}

//SHT31温湿度
 void i2c_master_init() {
    // I2C 配置
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = IIC_SDA; // SDA
    conf.scl_io_num = IIC_SCL; // SCL
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = 100000; // 100 kHz

    // 初始化 I2C
    i2c_param_config(I2C_NUM_0, &conf);
    i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0);
}

void sht31_read(float *temperature, float *humidity) {
    uint8_t data[6];
    uint16_t temp_raw, hum_raw;

    // 发送测量命令
    uint8_t command[2] = {0x2C, 0x06}; // 发送命令
    i2c_master_write_to_device(I2C_NUM_0, SHT31_I2C_ADDRESS, command, sizeof(command), 1000 / portTICK_PERIOD_MS);

    // 等待测量完成
    vTaskDelay(500 / portTICK_PERIOD_MS);

    // 读取数据
    i2c_master_read_from_device(I2C_NUM_0, SHT31_I2C_ADDRESS, data, sizeof(data), 1000 / portTICK_PERIOD_MS);

    // 处理温度和湿度数据
    temp_raw = ((data[0] << 8) | data[1]);
    hum_raw = ((data[3] << 8) | data[4]);

    *humidity = (hum_raw * 100.0) / 65535.0; // 湿度计算
    *temperature = -45.0 + (175.0 * (temp_raw / 65535.0)); // 温度计算
}

// -------------------------------新增代码---------------------------------------------------

// 回调函数--讯飞翻译
void onMessageCallback1(WebsocketsMessage message)
{
    StaticJsonDocument<1024*4> jsonDocument;
    DeserializationError error = deserializeJson(jsonDocument, message.data());

    if (!error)
    {
        int code = jsonDocument["code"];
        if (code != 0)
        {
            Serial.println(code);
            Serial.println(message.data());
            webSocketClient1.close();
        }
        else
        {
            Serial.println("xunfeiyun return message:");
            Serial.println(message.data());
            JsonArray ws = jsonDocument["data"]["result"]["ws"].as<JsonArray>();

            for (JsonVariant i : ws)
            {
                for (JsonVariant w : i["cw"].as<JsonArray>())
                {
                    askquestion += w["w"].as<String>();
                }
            }
            Serial.println(askquestion);
            int status = jsonDocument["data"]["status"];
            if (status == 2)
            {
                Serial.println("status == 2");
                webSocketClient1.close();
                if (askquestion == "")
                {
                    askquestion = "sorry, i can't hear you";
                    audio2.connecttospeech(askquestion.c_str(), "zh");
                }
                else
                {
                    //getText("user", askquestion);
                    //Serial.print("textxxxxx:");
                   // Serial.println(text);
                    Serial.print("askquestion:");
                    Serial.print(askquestion);
                    Answer = "";
                    lastsetence = false;
                    isReady = true;


                    chartgptquestion = askquestion;
                     autoUploadChartGPTFlag  = true;//上报给平台MQTT方式，等待AI回答



                   // ConnServer();
                }
            }
        }
    }
    else
    {
        Serial.println("error:");
        Serial.println(error.c_str());
        Serial.println(message.data());
    }
}

// 回调函数--录音
void onEventsCallback1(WebsocketsEvent event, String data)
{
    if (event == WebsocketsEvent::ConnectionOpened)
    {
        Serial.println("Send message to xunfeiyun");
        digitalWrite(led2, LOW);
        int silence = 0;
        int firstframe = 1;
        int j = 0;
        int voicebegin = 0;
        int voice = 0;
        DynamicJsonDocument doc(2500);

        while (1)
        {
            doc.clear();
            JsonObject data = doc.createNestedObject("data");
            audio1.Record();
            float rms = calculateRMS((uint8_t *)audio1.wavData[0], 1280);
            printf("录音情况xxxxx:%d %f\n", 0, rms);
            if (rms < noise)
            {
                if (voicebegin == 1)
                {
                    silence++;
                    // Serial.print("noise:");
                    // Serial.println(noise);
                }
            }
            else
            {
                voice++;
                if (voice >= 5)
                {
                    voicebegin = 1;
                }
                else
                {
                    voicebegin = 0;
                }
                silence = 0;
            }
            if (silence == 6)
            {
                data["status"] = 2;
                data["format"] = "audio/L16;rate=8000";
                data["audio"] = base64::encode((byte *)audio1.wavData[0], 1280);
                data["encoding"] = "raw";
                j++;

                String jsonString;
                serializeJson(doc, jsonString);

                webSocketClient1.send(jsonString);
                digitalWrite(led2, HIGH);
                delay(40);
                break;
            }
            if (firstframe == 1)
            {
                data["status"] = 0;
                data["format"] = "audio/L16;rate=8000";
                data["audio"] = base64::encode((byte *)audio1.wavData[0], 1280);
                data["encoding"] = "raw";
                j++;

                JsonObject common = doc.createNestedObject("common");
                common["app_id"] = appId1;

                JsonObject business = doc.createNestedObject("business");
                business["domain"] = "iat";
                business["language"] = "zh_cn";
                business["accent"] = "mandarin";
                business["vinfo"] = 1;
                business["vad_eos"] = 1000;

                String jsonString;
                serializeJson(doc, jsonString);

                webSocketClient1.send(jsonString);
                firstframe = 0;
                delay(40);
            }
            else
            {
                data["status"] = 1;
                data["format"] = "audio/L16;rate=8000";
                data["audio"] = base64::encode((byte *)audio1.wavData[0], 1280);
                data["encoding"] = "raw";

                String jsonString;
                serializeJson(doc, jsonString);

                webSocketClient1.send(jsonString);
                delay(40);
            }
        }
    }
    else if (event == WebsocketsEvent::ConnectionClosed)
    {
        Serial.println("Connnection1 Closed");
    }
    else if (event == WebsocketsEvent::GotPing)
    {
        Serial.println("Got a Ping!");
    }
    else if (event == WebsocketsEvent::GotPong)
    {
        Serial.println("Got a Pong!");
    }
}

// 连接讯飞
void ConnServer1()
{
    // Serial.println("url1:" + url1);
    webSocketClient1.onMessage(onMessageCallback1);
    webSocketClient1.onEvent(onEventsCallback1);
    // Connect to WebSocket
    Serial.println("Begin connect to server1......");
    if (webSocketClient1.connect(url1.c_str()))
    {
        Serial.println("Connected to server1!");
    }
    else
    {
        Serial.println("Failed to connect to server1!");
    }
}

// 播放
void voicePlay()
{
    if ((audio2.isplaying == 0) && Answer != "")
    {
        // String subAnswer = "";
        // String answer = "";
        // if (Answer.length() >= 100)
        //     subAnswer = Answer.substring(0, 100);
        // else
        // {
        //     subAnswer = Answer.substring(0);
        //     lastsetence = true;
        //     // startPlay = false;
        // }

        // Serial.print("subAnswer:");
        // Serial.println(subAnswer);
        int firstPeriodIndex = Answer.indexOf("。");
        int secondPeriodIndex = 0;

        if (firstPeriodIndex != -1)
        {
            secondPeriodIndex = Answer.indexOf("。", firstPeriodIndex + 1);
            if (secondPeriodIndex == -1)
                secondPeriodIndex = firstPeriodIndex;
        }
        else
        {
            secondPeriodIndex = firstPeriodIndex;
        }

        if (secondPeriodIndex != -1)
        {
            String answer = Answer.substring(0, secondPeriodIndex + 1);
            Serial.print("answer: ");
            Serial.println(answer);
            Answer = Answer.substring(secondPeriodIndex + 2);
            audio2.connecttospeech(answer.c_str(), "zh");
        }
        else
        {
            const char *chinesePunctuation = "？，：；,.";

            int lastChineseSentenceIndex = -1;

            for (int i = 0; i < Answer.length(); ++i)
            {
                char currentChar = Answer.charAt(i);

                if (strchr(chinesePunctuation, currentChar) != NULL)
                {
                    lastChineseSentenceIndex = i;
                }
            }

            if (lastChineseSentenceIndex != -1)
            {
                String answer = Answer.substring(0, lastChineseSentenceIndex + 1);
                audio2.connecttospeech(answer.c_str(), "zh");
                Answer = Answer.substring(lastChineseSentenceIndex + 2);
            }
        }
        startPlay = true;
    }
    else
    {
        // digitalWrite(led3, LOW);
    }
}

// 获取URL地址，
String getUrl(String Spark_url, String host, String path, String Date)
{

    // 拼接字符串
    String signature_origin = "host: " + host + "\n";
    signature_origin += "date: " + Date + "\n";
    signature_origin += "GET " + path + " HTTP/1.1";
    // signature_origin="host: spark-api.xf-yun.com\ndate: Mon, 04 Mar 2024 19:23:20 GMT\nGET /v3.5/chat HTTP/1.1";

    // hmac-sha256 加密
    unsigned char hmac[32];
    mbedtls_md_context_t ctx;
    mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
    const size_t messageLength = signature_origin.length();
    const size_t keyLength = APISecret.length();
    mbedtls_md_init(&ctx);
    mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
    mbedtls_md_hmac_starts(&ctx, (const unsigned char *)APISecret.c_str(), keyLength);
    mbedtls_md_hmac_update(&ctx, (const unsigned char *)signature_origin.c_str(), messageLength);
    mbedtls_md_hmac_finish(&ctx, hmac);
    mbedtls_md_free(&ctx);

    // base64 编码
    String signature_sha_base64 = base64::encode(hmac, sizeof(hmac) / sizeof(hmac[0]));

    // 替换Date
    Date.replace(",", "%2C");
    Date.replace(" ", "+");
    Date.replace(":", "%3A");
    String authorization_origin = "api_key=\"" + APIKey + "\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"" + signature_sha_base64 + "\"";
    String authorization = base64::encode(authorization_origin);
    String url = Spark_url + '?' + "authorization=" + authorization + "&date=" + Date + "&host=" + host;
    Serial.println(url);
    return url;
}

// 获取时间
void getTimeFromServer()
{
    String timeurl = "https://www.baidu.com";
    HTTPClient http;
    http.begin(timeurl);
    const char *headerKeys[] = {"Date"};
    http.collectHeaders(headerKeys, sizeof(headerKeys) / sizeof(headerKeys[0]));
    int httpCode = http.GET();
    Date = http.header("Date");
    Serial.println(Date);
    http.end();
    // delay(50); // 可以根据实际情况调整延时时间
}

void getText(String role, String content)
{
    checkLen(text);
    DynamicJsonDocument jsoncon(1024);
    jsoncon["role"] = role;
    jsoncon["content"] = content;
    text.add(jsoncon);
    jsoncon.clear();
    String serialized;
    serializeJson(text, serialized);
    Serial.print("text: ");
    Serial.println(serialized);
    // serializeJsonPretty(text, Serial);
}

int getLength(JsonArray textArray)
{
    int length = 0;
    for (JsonObject content : textArray)
    {
        const char *temp = content["content"];
        int leng = strlen(temp);
        length += leng;
    }
    return length;
}

void checkLen(JsonArray textArray)
{
    while (getLength(textArray) > 3000)
    {
        textArray.remove(0);
    }
    // return textArray;
}

DynamicJsonDocument gen_params(const char *appid, const char *domain)
{
    DynamicJsonDocument data(2048);

    JsonObject header = data.createNestedObject("header");
    header["app_id"] = appid;
    header["uid"] = "1234567";

    JsonObject parameter = data.createNestedObject("parameter");
    JsonObject chat = parameter.createNestedObject("chat");
    chat["domain"] = domain;
    chat["temperature"] = 0.7;
    chat["max_tokens"] = 1024;

    JsonObject payload = data.createNestedObject("payload");
    JsonObject message = payload.createNestedObject("message");

    JsonArray textArray = message.createNestedArray("text");
    for (const auto &item : text)
    {
        textArray.add(item);
    }
    return data;
}

float calculateRMS(uint8_t *buffer, int bufferSize)
{
    float sum = 0;
    int16_t sample;

    for (int i = 0; i < bufferSize; i += 2)
    {

        sample = (buffer[i + 1] << 8) | buffer[i];
        sum += sample * sample;
    }

    sum /= (bufferSize / 2);

    return sqrt(sum);
}

void controlAC(ACControlParams* params) {
    // Serial.println("controlAC fun run\n");
    String sensorname = params->sensorname;
    String sensorcmd = params->sensorcmd;
    JsonObject& cmddata = params->cmddata;
    if (sensorname == "ac") {  // 控制空调
        if(sensorcmd == "open")
            {
                Serial.println("open");

                uint8_t ac_mode = 1;//制热制冷-1制冷 4制热

                String ac_action = "";//下发的命令
                String ac_action_cmd = "";//调高
                ac_control = true;
                auto  extdata = cmddata["extdata"];
                // 空调的扩展指令 Temp温度 Mode加热/制冷--默认制冷 Fan风力--默认5auto

                if (extdata.containsKey("mode")) {
                    ac_mode = extdata["mode"];//制热制冷-1制冷 4制热
                } else {
                  Serial.println("mode does not exist");
                }

                if (extdata.containsKey("fan")) {
                    ac_fan = extdata["fan"];//风力 5auto默认  3low 2 med 1high
                }  else {
                  Serial.println("fan does not exist");
                }

                if (extdata.containsKey("temp")) {
                    ac_temp =  extdata["temp"];//温度
                }  else {
                  Serial.println("temp does not exist");
                }

                //扩展指令类型 action 用于判断指令具体作用是 调整还是打开
                if (extdata.containsKey("action")) {
                    String ac_actioncc =  extdata["action"];
                    ac_action = (String)ac_actioncc;
                }  else {
                  Serial.println("action does not exist");
                }

                if (extdata.containsKey("action_cmd")) {
                    String ac_action_cmdcc =  extdata["action_cmd"];
                    ac_action_cmd = (String)ac_action_cmdcc;

                }  else {
                  Serial.println("action_cmd does not exist");
                }

                Serial.println("ac_mode:"+ ac_mode);
                Serial.println("ac_fan:"+ ac_fan);
                Serial.println("ac_temp:"+ ac_temp);
                Serial.println("ac_action:"+ ac_action);
                Serial.println("ac_action_cmd:"+ ac_action_cmd);

                //打开和修改都公用的指令

                // 参数方式
                //打开空调-默认
                haier_ac.on();
                //设置模式  (1) V9014557 Remote in "A" setting. (Default)
                haier_ac.setModel(V9014557_A);
                // setPower
                haier_ac.setPower(1);
                //设置按钮 5是电源
                haier_ac.setButton(5);
                //制热制冷-1制冷 4制热
                haier_ac.setMode(ac_mode);
                //设置温度
                haier_ac.setTemp(ac_temp);
                // 设置风扇 风力 5auto默认  3low 2 med 1high
                haier_ac.setFan(ac_fan);

                //设置强劲模式(涡轮增压) 若传入的是on则Quiet = false;
                haier_ac.setTurbo(false);
                //设置静音 若传入的是on则 Turbo = false;
                haier_ac.setQuiet(false);

                //垂直摆动模式 Set the Vertical Swing mode of the A/C.
                haier_ac.setSwingV(2);//Middle 2
                // 水平摆动模式 Set the Horizontal Swing mode of the A/C.
                haier_ac.setSwingH(0);//Middle 0
                // Set the Sleep setting of the A/C.
                haier_ac.setSleep(false);
                // Set the Health (filter) setting of the A/C.
                haier_ac.setHealth(true);

                //设置定时开启/关闭空调 Set the Timer operating mode.  0关闭
                haier_ac.setTimerMode(0);
                //设置开启时间 Set the number of minutes of the On Timer setting.
                /// @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer.
                haier_ac.setOnTimer(0);
                //设置关闭时间 Set the number of minutes of the Off Timer setting.
                // @param[in] mins Nr. of Minutes for the Timer. `0` means disable the timer.
                haier_ac.setOffTimer(0);

                //设置锁定 Set the Lock setting of the A/C.
                haier_ac.setLock(false);

                //进行调整空调文档数据  根据扩展指令中的action字段，判断是：后续调整、第一次打开
                if (ac_action == "change")
                {
                    Serial.println("change okxxxxxxxxxxxxx");

                    // 如果有temp fan直接使用此值，如果没有temp则直接进行加/减1
                    if (extdata.containsKey("temp")) {
                        Serial.println("temp is exist 不需要操作 ");
                    }  else if (extdata.containsKey("fan")) {
                        Serial.println("fan is exist 不需要操作 ");
                    }  else{
                        //本地记时间，进行加减操作
                        Serial.println("temp does not exist");
                        if (ac_action_cmd == "temp_height")
                        {
                        Serial.println("height okxxxxxxxxxxxxx");

                          haier_ac.setButton(0); //0 是新增  1是减少
                            // ac_temp =  haier_ac.getTemp();
                            //设置温度
                            ac_temp = ac_temp + 1;
                            haier_ac.setTemp(ac_temp);
                        }else if (ac_action_cmd == "temp_low") {

                          Serial.println("low okxxxxxxxxxxxxx");
                          haier_ac.setButton(1); //0 是新增  1是减少
                            // ac_temp =  haier_ac.getTemp();
                            //设置温度
                            ac_temp = ac_temp - 1;
                            haier_ac.setTemp(ac_temp);
                        }else if (ac_action_cmd == "fan_height") {  //风力三个档位 3最小 2居中 1最大

                          Serial.println("low okxxxxxxxxxxxxx");
                          if (ac_fan == 5 )//自动模式
                          {
                            ac_fan = 3;
                          }else if (ac_fan == 3)
                          {
                            ac_fan = 2;
                          }else if (ac_fan == 2)
                          {
                            ac_fan = 1;
                          }else
                          {
                            ac_fan = 1;//最大
                          }

                          haier_ac.setFan(ac_fan); //3最小 2居中 1最大

                        }else if (ac_action_cmd == "fan_low") {

                          Serial.println("low okxxxxxxxxxxxxx");
                           if (ac_fan == 1 )
                          {
                            ac_fan = 2;
                          }else if (ac_fan == 2)
                          {
                            ac_fan = 3;
                          }else if (ac_fan == 3)
                          {
                            ac_fan = 5;
                          }else
                          {
                            ac_fan = 5;//自动模式
                          }

                          haier_ac.setFan(ac_fan); //3最小 2居中 1最大

                        }

                    }
                    Serial.println("send okxxxxxxxxxxxxx");

                    //最后 发送红外
                    haier_ac.send();

                    }else if (ac_action == "open"){
                      //默认的打开空调
                        Serial.println("ac_action open okxxxxxxxxxxxxx");

                        // 发射指令
                        Serial.println("a power_on capture from IRrecvDumpV2");
                        //指令方式
                        // irsend.sendRaw(power_on, 229, 38);  // Send a raw data capture at 38kHz.

                        //设置温度
                        haier_ac.setTemp(ac_temp);
                        haier_ac.setFan(ac_fan);

                        //最后 发送红外
                        haier_ac.send();

                    }else{
                        Serial.println("ac_action err!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                    }

                    // 修改空调flag状态
                    ac = "open";
                    autoUploadFlag = true;
            
            }else if(sensorcmd == "close")
            {
                Serial.println("close");
                Serial.println("a power_on capture from IRrecvDumpV2");
                // irsend.sendRaw(power_off, 229, 38);  // Send a raw data capture at 38kHz.
                haier_ac.off();
                haier_ac.send();
                ac = "close";
                autoUploadFlag = true;

            }else{
                Serial.println(sensorcmd);
            }
    }
}


void loop() {
    while(1);
}
